import os
import shutil
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
import requests
from PIL import Image, ImageOps
import threading
from datetime import datetime
import time
import random
import queue
import subprocess
import re

# Пути к директориям и файлам
avatars_path = r"C:\Users\1\Desktop\VS 2022\Загрузка аватарок ВК\аватарки"
uploaded_path = os.path.join(avatars_path, "Загруженные")
tokens_file_path = r"C:\Users\1\Desktop\VS 2022\Загрузка аватарок ВК\токены для загруки аватарок.txt"
failed_accounts_file = r"C:\Users\1\Desktop\VS 2022\Загрузка аватарок ВК\неудачные.txt"

# Глобальные переменные для токенов и списка аватарок
tokens = []
avatars = []

# Параметры рамки для обработки аватарки
border_size = 110
border_color = 'white'

# ----------------------------------------------------------------------------
# Очереди для логирования и статусы
# ----------------------------------------------------------------------------

log_queue = queue.Queue()
success_queue = queue.Queue()
fail_queue = queue.Queue()
ip_country_queue = queue.Queue()

# Объект Events для паузы и возобновления
pause_event = threading.Event()
pause_event.set()

# ----------------------------------------------------------------------------
# Переменные для таймеров
# ----------------------------------------------------------------------------
start_time = None
total_runtime = 0
next_action_time = 0
timer_running = False
countdown_running = False

# ----------------------------------------------------------------------------
# Создание главного окна с красивым оформлением
# ----------------------------------------------------------------------------

root = tk.Tk()
root.title("Загрузка аватарок ВК")
root.geometry("1200x700")  # Увеличена высота для таймеров
root.configure(bg="#2C3E50")

style = ttk.Style(root)
style.theme_use("clam")

default_font = ("Segoe UI", 11)
style.configure("TFrame", background="#2C3E50")
style.configure("TLabel", background="#2C3E50", foreground="#ECF0F1", font=default_font)
style.configure("TButton", font=("Segoe UI", 11, "bold"), padding=6)
style.configure("TEntry", padding=4, font=default_font)

style.map("TButton",
          foreground=[("active", "#ECF0F1")],
          background=[("active", "#2980B9")])

# ----------------------------------------------------------------------------
# Переменные для статистики и таймеров
# ----------------------------------------------------------------------------

total_accounts = tk.StringVar(value="Всего аккаунтов: 0")
processed_photos = tk.StringVar(value="Обработано фотографий: 0")
remaining_photos = tk.StringVar(value="Осталось фотографий: 0")
successful_uploads = tk.StringVar(value="Успешных добавлений: 0")
failed_uploads = tk.StringVar(value="Неуспешных добавлений: 0")
current_wifi_status = tk.StringVar(value="Wi-Fi: Сканирование...")
current_ip_country_status = tk.StringVar(value="IP: Определение... (Страна: ...)")

# Новые переменные для таймеров
runtime_status = tk.StringVar(value="Время работы: 00:00:00")
countdown_status = tk.StringVar(value="До следующего действия: --")

delay_min = tk.StringVar(value="20")
delay_max = tk.StringVar(value="40")

INFO_COLOR = "white"
SUCCESS_COLOR = "#2ECC71"
ERROR_COLOR = "#E74C3C"
SEPARATOR_COLOR = "#3498DB"
DEFAULT_TEXT_COLOR = "#ECF0F1"
TIMER_COLOR = "#F39C12"  # Цвет для таймеров

token_counter = 0
auto_scroll_enabled = tk.BooleanVar(value=True)

# Глобальные ссылки на метки для обновления цвета
ip_country_label_ui_ref = None
wifi_label_ui_ref = None
runtime_label_ui_ref = None
countdown_label_ui_ref = None

# ----------------------------------------------------------------------------
# Функции для таймеров
# ----------------------------------------------------------------------------

def start_runtime_timer():
    """Запускает таймер общего времени работы"""
    global start_time, timer_running
    start_time = time.time()
    timer_running = True
    update_runtime_display()

def stop_runtime_timer():
    """Останавливает таймер общего времени работы"""
    global timer_running, total_runtime
    if timer_running and start_time:
        total_runtime += time.time() - start_time
        timer_running = False

def update_runtime_display():
    """Обновляет отображение времени работы"""
    global runtime_label_ui_ref
    if timer_running and start_time:
        current_runtime = total_runtime + (time.time() - start_time)
        hours = int(current_runtime // 3600)
        minutes = int((current_runtime % 3600) // 60)
        seconds = int(current_runtime % 60)
        runtime_status.set(f"Время работы: {hours:02d}:{minutes:02d}:{seconds:02d}")
        
        if runtime_label_ui_ref:
            runtime_label_ui_ref.configure(foreground=TIMER_COLOR)
    
    if timer_running:
        root.after(1000, update_runtime_display)

def start_countdown_timer(delay_seconds):
    """Запускает обратный отсчёт до следующего действия"""
    global next_action_time, countdown_running
    next_action_time = delay_seconds
    countdown_running = True
    update_countdown_display()

def update_countdown_display():
    """Обновляет отображение обратного отсчёта"""
    global next_action_time, countdown_running, countdown_label_ui_ref
    
    if countdown_running and next_action_time > 0:
        minutes = int(next_action_time // 60)
        seconds = int(next_action_time % 60)
        countdown_status.set(f"До следующего действия: {minutes:02d}:{seconds:02d}")
        
        if countdown_label_ui_ref:
            countdown_label_ui_ref.configure(foreground=TIMER_COLOR)
        
        next_action_time -= 1
        root.after(1000, update_countdown_display)
    else:
        countdown_running = False
        countdown_status.set("До следующего действия: --")
        if countdown_label_ui_ref:
            countdown_label_ui_ref.configure(foreground=DEFAULT_TEXT_COLOR)

# ----------------------------------------------------------------------------
# Функции логирования и работы с очередями
# ----------------------------------------------------------------------------

def log(message, color=INFO_COLOR):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log_queue.put((f"[{timestamp}] {message}\n", color))

def log_success_token(token_info: str):
    success_queue.put(token_info)

def log_fail_token(token_info: str):
    fail_queue.put(token_info)

def process_log_queue():
    try:
        while True:
            msg, color = log_queue.get_nowait()
            log_text.insert(tk.END, msg, color)
            log_text.tag_config(color, foreground=color)
            if auto_scroll_enabled.get():
                log_text.see(tk.END)
    except queue.Empty:
        pass
    root.after(100, process_log_queue)

def process_success_queue():
    try:
        while True:
            token_info = success_queue.get_nowait()
            success_text.insert(tk.END, token_info + "\n")
            if auto_scroll_enabled.get():
                success_text.see(tk.END)
    except queue.Empty:
        pass
    root.after(100, process_success_queue)

def process_fail_queue():
    try:
        while True:
            token_info = fail_queue.get_nowait()
            fail_text.insert(tk.END, token_info + "\n")
            if auto_scroll_enabled.get():
                fail_text.see(tk.END)
    except queue.Empty:
        pass
    root.after(100, process_fail_queue)

# ----------------------------------------------------------------------------
# Функция получения SSID Wi-Fi
# ----------------------------------------------------------------------------

def get_current_wifi_ssid():
    try:
        process = subprocess.Popen(['netsh', 'wlan', 'show', 'interfaces'],
                                     stdout=subprocess.PIPE,
                                     text=True,
                                     encoding='utf-8',
                                     errors='ignore',
                                     creationflags=subprocess.CREATE_NO_WINDOW)
        stdout, stderr = process.communicate(timeout=5)
        if process.returncode == 0:
            for line in stdout.splitlines():
                if "SSID" in line and "BSSID" not in line:
                    match = re.search(r":\s*(.+)", line)
                    if match:
                        ssid = match.group(1).strip()
                        if ssid:
                            return ssid
            return "Нет подключения"
        else:
            return "Ошибка опроса"
    except FileNotFoundError:
        return "netsh не найден"
    except subprocess.TimeoutExpired:
        return "Тайм-аут опроса"
    except Exception as e:
        return "Ошибка Wi-Fi"

def update_wifi_display():
    global wifi_label_ui_ref
    ssid = get_current_wifi_ssid()
    current_wifi_status.set(f"Wi-Fi: {ssid}")
    if "Ошибка" in ssid or "Нет подключения" in ssid or "не найден" in ssid:
        if wifi_label_ui_ref: 
            wifi_label_ui_ref.configure(foreground=ERROR_COLOR)
    else:
        if wifi_label_ui_ref: 
            wifi_label_ui_ref.configure(foreground=DEFAULT_TEXT_COLOR)
    root.after(5000, update_wifi_display)

# ----------------------------------------------------------------------------
# Функции для IP и страны
# ----------------------------------------------------------------------------

def get_external_ip_and_country():
    ip_address_val = "Ошибка (IP)"
    country_val = "Ошибка (Страна)"
    try:
        response = requests.get("http://ip-api.com/json/?fields=status,message,country,countryCode,query,city", timeout=4)
        response.raise_for_status()
        data = response.json()
        if data.get("status") == "success":
            ip_address_val = data.get("query", ip_address_val)
            country_name = data.get("country")
            country_code = data.get("countryCode")
            city_name = data.get("city", "")

            if country_name:
                country_val = country_name
            elif country_code:
                country_val = country_code
            else:
                country_val = "N/A"
            
            if city_name and country_val != "N/A":
                country_val = f"{city_name}, {country_val}"
            elif city_name:
                country_val = city_name

        else:
            error_message = data.get("message", "Неизвестная ошибка от ip-api.com")
            log(f"Ошибка от ip-api.com (status fail): {error_message}", color=ERROR_COLOR)
    except requests.exceptions.Timeout:
        log(f"Таймаут при запросе к ip-api.com", color=ERROR_COLOR)
    except requests.exceptions.RequestException as e:
        log(f"Ошибка запроса к ip-api.com: {e}", color=ERROR_COLOR)
    except Exception as e:
        log(f"Непредвиденная ошибка в get_external_ip_and_country: {e}", color=ERROR_COLOR)
    return ip_address_val, country_val

def _fetch_ip_and_country_data():
    ip, country = get_external_ip_and_country()
    ip_country_queue.put((ip, country))

def process_ip_country_queue():
    global ip_country_label_ui_ref
    try:
        ip, country = ip_country_queue.get_nowait()
        text_to_set = f"IP: {ip} (Локация: {country})"
        current_ip_country_status.set(text_to_set)
        
        if ip_country_label_ui_ref:
            if "Ошибка" in ip or "Ошибка" in country or "N/A" in country:
                ip_country_label_ui_ref.configure(foreground=ERROR_COLOR)
            else:
                ip_country_label_ui_ref.configure(foreground=DEFAULT_TEXT_COLOR)
    except queue.Empty:
        pass
    root.after(200, process_ip_country_queue)

def update_ip_country_display():
    threading.Thread(target=_fetch_ip_and_country_data, daemon=True).start()
    root.after(15000, update_ip_country_display)

# ----------------------------------------------------------------------------
# Функции работы с файлами и обновление информации
# ----------------------------------------------------------------------------

def log_failed_account(token):
    try:
        with open(failed_accounts_file, 'a', encoding='utf-8') as file:
            file.write(f"{token}\n")
        log(f"Записан неудачный токен: {token}", color=ERROR_COLOR)
    except Exception as e:
        log(f"Ошибка записи неудачного токена: {str(e)}", color=ERROR_COLOR)

def load_tokens():
    global tokens
    if os.path.exists(tokens_file_path):
        with open(tokens_file_path, 'r', encoding='utf-8') as file:
            tokens = [line.strip() for line in file if line.strip()]
        total_accounts.set(f"Всего аккаунтов: {len(tokens)}")
        log(f"Загружено токенов: {len(tokens)}", color=SUCCESS_COLOR)
    else:
        log("Файл с токенами не найден.", color=ERROR_COLOR)

def load_avatars():
    global avatars
    if os.path.exists(avatars_path):
        avatars = [os.path.join(avatars_path, f)
                   for f in os.listdir(avatars_path)
                   if os.path.isfile(os.path.join(avatars_path, f)) and f != "prepared_image.png"]
        remaining_photos.set(f"Осталось фотографий: {len(avatars)}")
        log(f"Загружено аватарок: {len(avatars)}", color=SUCCESS_COLOR)
    else:
        log("Директория с аватарками не найдена.", color=ERROR_COLOR)

def update_info():
    log("Нажата кнопка 'Обновить информацию'", color=INFO_COLOR)
    load_tokens()
    load_avatars()
    processed_photos.set("Обработано фотографий: 0")
    successful_uploads.set("Успешных добавлений: 0")
    failed_uploads.set("Неуспешных добавлений: 0")
    os.makedirs(uploaded_path, exist_ok=True)
    log("Информация обновлена.", color=SUCCESS_COLOR)

def get_user_info(token):
    url = "https://api.vk.com/method/users.get"
    params = {'access_token': token, 'v': '5.131'}
    try:
        response = requests.get(url, params=params, timeout=10)
        if response.status_code == 200:
            data = response.json()
            if 'response' in data and len(data['response']) > 0:
                return data['response'][0]
        log(f"Ошибка получения информации о пользователе: {response.text}", color=ERROR_COLOR)
    except Exception as e:
        log(f"Исключение при получении информации о пользователе: {str(e)}", color=ERROR_COLOR)
    return None

def get_upload_url(token):
    url = "https://api.vk.com/method/photos.getOwnerPhotoUploadServer"
    params = {'access_token': token, 'v': '5.131'}
    try:
        response = requests.get(url, params=params, timeout=10)
        if response.status_code == 200:
            return response.json().get('response', {}).get('upload_url')
        else:
            log(f"Ошибка получения URL: {response.text}", color=ERROR_COLOR)
    except Exception as e:
        log(f"Исключение при получении URL: {str(e)}", color=ERROR_COLOR)
    return None

def save_photo(data, token):
    url = "https://api.vk.com/method/photos.saveOwnerPhoto"
    params = {
        'server': data.get('server'),
        'photo': data.get('photo'),
        'hash': data.get('hash'),
        'access_token': token,
        'v': '5.131'
    }
    try:
        response = requests.post(url, params=params, timeout=10)
        if response.status_code == 200:
            return response.json().get('response', {})
    except Exception as e:
        log(f"Исключение при сохранении фото: {str(e)}", color=ERROR_COLOR)
    return {}

def delete_last_wall_post(token):
    url = "https://api.vk.com/method/wall.get"
    params = {'access_token': token, 'v': '5.131', 'count': 1}
    try:
        response = requests.get(url, params=params, timeout=10)
        data = response.json()
        if response.status_code == 200 and 'response' in data:
            items = data['response'].get('items', [])
            if items:
                last_post_id = items[0]['id']
                log(f"Последняя запись найдена: ID {last_post_id}", color=INFO_COLOR)
                delete_url = "https://api.vk.com/method/wall.delete"
                delete_params = {'access_token': token, 'v': '5.131', 'post_id': last_post_id}
                delete_response = requests.post(delete_url, params=delete_params, timeout=10)
                if delete_response.status_code == 200:
                    log(f"Последняя запись успешно удалена: ID {last_post_id}", color=SUCCESS_COLOR)
                else:
                    log(f"Ошибка при удалении записи: {delete_response.text}", color=ERROR_COLOR)
            else:
                log("Нет записей для удаления.", color=INFO_COLOR)
        else:
            log(f"Ошибка получения записей со стены: {response.text}", color=ERROR_COLOR)
    except Exception as e:
        log(f"Исключение при удалении записи: {str(e)}", color=ERROR_COLOR)

def prepare_image(image_path):
    try:
        image = Image.open(image_path)
        if image.width != image.height:
            new_size = max(image.width, image.height)
            new_image = Image.new("RGBA", (new_size, new_size), (255, 255, 255, 0))
            new_image.paste(image, ((new_size - image.width) // 2, (new_size - image.height) // 2))
        else:
            new_image = image.convert("RGBA")

        new_image_with_border = ImageOps.expand(new_image, border=border_size, fill=border_color)
        
        prepared_image_path = os.path.join(avatars_path, "prepared_image.png")
        new_image_with_border.save(prepared_image_path, format="PNG")
        return prepared_image_path
    except Exception as e:
        log(f"Ошибка подготовки изображения: {str(e)}", color=ERROR_COLOR)
        return None

def upload_avatar():
    global token_counter
    processed_count = 0
    success_count = 0
    fail_count = 0

    while tokens and avatars:
        pause_event.wait()

        token_counter += 1
        token = tokens.pop(0)
        avatar_file = avatars.pop(0)

        processed_count += 1
        processed_photos.set(f"Обработано фотографий: {processed_count}")
        remaining_photos.set(f"Осталось фотографий: {len(avatars)}")

        user_info = get_user_info(token)
        user_name = f"{user_info.get('first_name', '')} {user_info.get('last_name', '')}" if user_info else "Неизвестный пользователь"

        log(f"{token_counter}. Токен (пользователь: {user_name}): {token}", color=INFO_COLOR)
        log(f"Обработка файла: {avatar_file}", color=INFO_COLOR)

        upload_url = get_upload_url(token)
        if not upload_url:
            log(f"Не удалось получить URL для загрузки для {user_name}.", color=ERROR_COLOR)
            fail_count += 1
            failed_uploads.set(f"Неуспешных добавлений: {fail_count}")
            log_fail_token(token)
            log_failed_account(token)
            try: 
                os.remove(avatar_file)
            except Exception as e: 
                log(f"Ошибка удаления файла: {str(e)}", color=ERROR_COLOR)
            delay_and_continue()
            continue

        upload_success = False
        response_from_server = None
        for attempt in range(1, 4):
            prepared_image_path = prepare_image(avatar_file)
            if not prepared_image_path:
                log(f"Попытка {attempt}: Не удалось подготовить изображение для {user_name}.", color=ERROR_COLOR)
                continue
            try:
                with open(prepared_image_path, 'rb') as file_to_upload:
                    files = {'photo': file_to_upload}
                    response_from_server = requests.post(upload_url, files=files, timeout=20)
                if response_from_server.status_code != 200:
                    log(f"Попытка {attempt}: Ошибка загрузки фото для {user_name}: {response_from_server.text}", color=ERROR_COLOR)
                else:
                    upload_success = True
                    break
            except Exception as e:
                log(f"Попытка {attempt}: Исключение при загрузке: {str(e)}", color=ERROR_COLOR)
            finally:
                if os.path.exists(prepared_image_path):
                    try: 
                        os.remove(prepared_image_path)
                    except Exception as e: 
                        log(f"Ошибка удаления подготовленного изображения: {str(e)}", color=ERROR_COLOR)
            if attempt < 3 and not upload_success:
                log(f"Повторная попытка загрузки фото для {user_name}...", color=INFO_COLOR)
                time.sleep(1)

        if not upload_success:
            log(f"Не удалось загрузить фото для {user_name} после 3 попыток.", color=ERROR_COLOR)
            fail_count += 1
            failed_uploads.set(f"Неуспешных добавлений: {fail_count}")
            log_fail_token(token)
            log_failed_account(token)
            try: 
                os.remove(avatar_file)
            except Exception as e: 
                log(f"Ошибка удаления неудачной фотографии: {str(e)}", color=ERROR_COLOR)
            delay_and_continue()
            continue

        log(f"Фото успешно загружено на сервер для {user_name}.", color=SUCCESS_COLOR)
        try: 
            upload_data = response_from_server.json()
        except Exception as e: 
            log(f"Ошибка преобразования ответа в JSON: {str(e)}", color=ERROR_COLOR)
            upload_data = {}
        
        save_response = save_photo(upload_data, token)
        if save_response.get("saved") == 1:
            log(f"Фото сохранено для {user_name}. ID поста: {save_response.get('post_id')}", color=SUCCESS_COLOR)
            delete_last_wall_post(token)
            success_count += 1
            successful_uploads.set(f"Успешных добавлений: {success_count}")
            log_success_token(token)
        else:
            log(f"Ошибка сохранения фото для {user_name}. Ответ: {save_response}", color=ERROR_COLOR)
            fail_count += 1
            failed_uploads.set(f"Неуспешных добавлений: {fail_count}")
            log_fail_token(token)
            log_failed_account(token)
        
        try:
            destination_path = os.path.join(uploaded_path, os.path.basename(avatar_file))
            shutil.move(avatar_file, destination_path)
        except Exception as e: 
            log(f"Ошибка перемещения оригинального файла: {str(e)}", color=ERROR_COLOR)
        
        log("—" * 50, color=SEPARATOR_COLOR)
        delay_and_continue()

    log("Загрузка аватарок завершена. Все операции выполнены.", color=SUCCESS_COLOR)
    stop_runtime_timer()  # Останавливаем таймер общего времени
    if upload_button: 
        upload_button["state"] = "normal"
    if pause_button: 
        pause_button["state"] = "disabled"
    if resume_button: 
        resume_button["state"] = "disabled"

def delay_and_continue():
    try:
        min_delay_val = float(delay_min.get())
        max_delay_val = float(delay_max.get())
        if max_delay_val < min_delay_val: 
            max_delay_val = min_delay_val
        delay = random.uniform(min_delay_val, max_delay_val)
        log(f"Задержка перед следующим аккаунтом: {delay:.2f} секунд", color=INFO_COLOR)
        
        # Запускаем обратный отсчёт
        start_countdown_timer(int(delay))
        
        time.sleep(delay)
    except ValueError:
        log("Ошибка в значениях задержки. Установлена задержка: 2.5 секунды.", color=ERROR_COLOR)
        start_countdown_timer(3)  # Показываем обратный отсчёт для стандартной задержки
        time.sleep(2.5)

def start_upload_thread():
    log("Нажата кнопка 'Запустить'", color=INFO_COLOR)
    upload_button["state"] = "disabled"
    pause_button["state"] = "normal"
    resume_button["state"] = "disabled"
    pause_event.set()
    
    # Запускаем таймер общего времени работы
    start_runtime_timer()
    
    threading.Thread(target=upload_avatar, daemon=True).start()

def pause_process():
    log("Нажата кнопка 'Приостановить'", color=INFO_COLOR)
    pause_event.clear()
    pause_button["state"] = "disabled"
    resume_button["state"] = "normal"
    
    # Останавливаем таймер при паузе
    stop_runtime_timer()

def resume_process():
    log("Нажата кнопка 'Восстановить'", color=INFO_COLOR)
    pause_event.set()
    resume_button["state"] = "disabled"
    pause_button["state"] = "normal"
    
    # Возобновляем таймер
    start_runtime_timer()

def clear_all_logs():
    log_text.delete(1.0, tk.END)
    success_text.delete(1.0, tk.END)
    fail_text.delete(1.0, tk.END)

last_clicked_text_widget = None

def create_context_menu(event):
    global last_clicked_text_widget
    last_clicked_text_widget = event.widget
    context_menu.tk_popup(event.x_root, event.y_root)

def copy_selected_text():
    global last_clicked_text_widget
    if not last_clicked_text_widget: 
        return
    try:
        selected_text = last_clicked_text_widget.selection_get()
        root.clipboard_clear()
        root.clipboard_append(selected_text)
    except tk.TclError: 
        pass

# ----------------------------------------------------------------------------
# Построение интерфейса
# ----------------------------------------------------------------------------

main_frame = ttk.Frame(root, padding=10)
main_frame.pack(fill=tk.BOTH, expand=True)

top_frame = ttk.Frame(main_frame)
top_frame.pack(fill=tk.X, pady=5)

upload_button = ttk.Button(top_frame, text="Запустить", command=start_upload_thread, width=15)
upload_button.pack(side=tk.LEFT, padx=5)
pause_button = ttk.Button(top_frame, text="Приостановить", command=pause_process, width=15, state="disabled")
pause_button.pack(side=tk.LEFT, padx=5)
resume_button = ttk.Button(top_frame, text="Восстановить", command=resume_process, width=15, state="disabled")
resume_button.pack(side=tk.LEFT, padx=5)
update_button = ttk.Button(top_frame, text="Обновить информацию", command=update_info, width=20)
update_button.pack(side=tk.LEFT, padx=5)

delay_label = ttk.Label(top_frame, text="Задержка (сек):")
delay_label.pack(side=tk.LEFT, padx=(10, 5))
delay_min_entry = ttk.Entry(top_frame, textvariable=delay_min, width=5)
delay_min_entry.pack(side=tk.LEFT)
delay_dash_label = ttk.Label(top_frame, text="-")
delay_dash_label.pack(side=tk.LEFT)
delay_max_entry = ttk.Entry(top_frame, textvariable=delay_max, width=5)
delay_max_entry.pack(side=tk.LEFT)

clear_log_button = ttk.Button(top_frame, text="Очистить все журналы", command=clear_all_logs, width=18)
clear_log_button.pack(side=tk.LEFT, padx=5)

stats_frame = ttk.Frame(main_frame)
stats_frame.pack(fill=tk.X, pady=5)

# Основная статистика
ttk.Label(stats_frame, textvariable=total_accounts).pack(anchor=tk.W)
ttk.Label(stats_frame, textvariable=processed_photos).pack(anchor=tk.W)
ttk.Label(stats_frame, textvariable=remaining_photos).pack(anchor=tk.W)
ttk.Label(stats_frame, textvariable=successful_uploads).pack(anchor=tk.W)
ttk.Label(stats_frame, textvariable=failed_uploads).pack(anchor=tk.W)

# Разделитель
separator = ttk.Separator(stats_frame, orient='horizontal')
separator.pack(fill=tk.X, pady=(5, 5))

# Информация о подключении
wifi_label_ui_ref = ttk.Label(stats_frame, textvariable=current_wifi_status)
wifi_label_ui_ref.pack(anchor=tk.W)

ip_country_label_ui_ref = ttk.Label(stats_frame, textvariable=current_ip_country_status)
ip_country_label_ui_ref.pack(anchor=tk.W, pady=(2, 0))

# Разделитель
separator2 = ttk.Separator(stats_frame, orient='horizontal')
separator2.pack(fill=tk.X, pady=(5, 5))

# Таймеры
runtime_label_ui_ref = ttk.Label(stats_frame, textvariable=runtime_status, font=("Segoe UI", 11, "bold"))
runtime_label_ui_ref.pack(anchor=tk.W)

countdown_label_ui_ref = ttk.Label(stats_frame, textvariable=countdown_status, font=("Segoe UI", 11, "bold"))
countdown_label_ui_ref.pack(anchor=tk.W, pady=(2, 0))

bottom_frame = ttk.Frame(main_frame)
bottom_frame.pack(fill=tk.BOTH, expand=True, pady=(5, 0))
bottom_frame.columnconfigure(0, weight=1)
bottom_frame.columnconfigure(1, weight=1) 
bottom_frame.columnconfigure(2, weight=1)

log_frame = ttk.Frame(bottom_frame, relief=tk.SUNKEN)
log_frame.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
ttk.Label(log_frame, text="Общий журнал").pack(anchor="n")
log_text = tk.Text(log_frame, height=15, wrap=tk.WORD, bg="#34495E", fg="white", font=default_font)
log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=2)
log_scroll = ttk.Scrollbar(log_frame, orient=tk.VERTICAL, command=log_text.yview)
log_scroll.pack(side=tk.RIGHT, fill=tk.Y)
log_text.config(yscrollcommand=log_scroll.set)

success_frame = ttk.Frame(bottom_frame, relief=tk.SUNKEN)
success_frame.grid(row=0, column=1, sticky="nsew", padx=5, pady=5)
ttk.Label(success_frame, text="Успешные токены").pack(anchor="n")
success_text = tk.Text(success_frame, height=15, wrap=tk.WORD, bg="#34495E", fg="white", font=default_font)
success_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=2)
success_scroll = ttk.Scrollbar(success_frame, orient=tk.VERTICAL, command=success_text.yview)
success_scroll.pack(side=tk.RIGHT, fill=tk.Y)
success_text.config(yscrollcommand=success_scroll.set)

fail_frame = ttk.Frame(bottom_frame, relief=tk.SUNKEN)
fail_frame.grid(row=0, column=2, sticky="nsew", padx=5, pady=5)
ttk.Label(fail_frame, text="Неуспешные токены").pack(anchor="n")
fail_text = tk.Text(fail_frame, height=15, wrap=tk.WORD, bg="#34495E", fg="white", font=default_font)
fail_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=2)
fail_scroll = ttk.Scrollbar(fail_frame, orient=tk.VERTICAL, command=fail_text.yview)
fail_scroll.pack(side=tk.RIGHT, fill=tk.Y)
fail_text.config(yscrollcommand=fail_scroll.set)

context_menu = tk.Menu(root, tearoff=0)
context_menu.add_command(label="Копировать", command=copy_selected_text)
context_menu.add_separator()
context_menu.add_checkbutton(label="Автопрокрутка", variable=auto_scroll_enabled)

log_text.bind("<Button-3>", create_context_menu)
success_text.bind("<Button-3>", create_context_menu)
fail_text.bind("<Button-3>", create_context_menu)

# Запуск обработки очередей и первоначальное обновление информации
process_log_queue()
process_success_queue()
process_fail_queue()
update_info()

# Запуск периодического обновления Wi-Fi и IP/Страны
update_wifi_display()
process_ip_country_queue()
update_ip_country_display()

root.mainloop()
